﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Database;
using System.Xml;
using System.Data;
using System.Windows.Forms;
using System.Data.Common;
using System.DirectoryServices;
using MacomberMapSystem.Common.User_Interfaces.Database;
using System.ComponentModel;
using MacomberMapSystem.Common.Processing;

namespace MacomberMapSystem.Common.Serialization
{
    /// <summary>
    /// This interface provides information on a class that can be processed, containing relevant dictionaries and lists for information
    /// </summary>
    public class MM_Repository: MM_Serializable
    {
        #region Variable declarations
        /// <summary>Whether the substation/line editor is in place</summary>
        public bool EditMode = false;

        /// <summary>The XML configuration for our application</summary>
        public XmlDocument xConfig;

        /// <summary>The connector to the MM SQL database</summary>
        public MM_Database_Connector Db; 

        /// <summary>The currently active user</summary>
        public MM_Database_User CurrentUser = null;

        /// <summary>The list of active models</summary>
        public Dictionary<int, MM_Database_Model> Model_Collection = new Dictionary<int, MM_Database_Model>();

        /// <summary>Our collection of users</summary>
        public Dictionary<int, MM_Database_User> User_Collection = new Dictionary<int, MM_Database_User>();

        /// <summary>Our collection of active processes.</summary>
        public List<CIM_Processor> ActiveProcesses = new List<CIM_Processor>();

        /// <summary>The selected user name</summary>
        public string UserName=Environment.UserName;

        /// <summary>The selected user name</summary>
        public string UserDomain=Environment.UserDomainName;

        /// <summary>
        /// Our delegate for background worker -related events.
        /// </summary>
        /// <param name="Worker"></param>
        /// <param name="Name"></param>
        public delegate void BackgroundWorkerDelegate(BackgroundWorker Worker, String Name);

        /// <summary>Our event for a background worker being added</summary>
        public event BackgroundWorkerDelegate WorkerAdded;

        #endregion

        #region Initialization
        /// <summary>Initialize an empty repository</summary>
        public MM_Repository() : base(null, null) { }

        /// <summary>
        /// Initialize a repository from a data element (e.g., for a CIM model)
        /// </summary>
        /// <param name="dRd"></param>
        /// <param name="Repository"></param>
        public MM_Repository(DbDataReader dRd, MM_Repository Repository)
            : base(dRd, null, Repository)
        { }
        #endregion

        #region Interfacing
        /// <summary>
        /// Build a data table/view for showing sorted models
        /// </summary>
        /// <param name="ModelCombo">The combo box for models</param>
        public void BuildModelCombo(ComboBox ModelCombo)
        {           
            ModelCombo.Sorted = false;
            DataTable OutModels = new DataTable("OutModels");
            OutModels.Columns.Add("Name", typeof(string));
            OutModels.PrimaryKey = new DataColumn[] { OutModels.Columns.Add("Model", typeof(MM_Database_Model)) };
            foreach (DataColumn dCol in OutModels.Columns)
                dCol.AllowDBNull = true;
            OutModels.Rows.Add();
            foreach (MM_Database_Model Model in Model_Collection.Values)
                OutModels.Rows.Add(Model.ToString(), Model);
            DataView OutView = new DataView(OutModels);
            OutView.Sort = "Model";
            ModelCombo.DisplayMember = "Name";
            ModelCombo.ValueMember = "Model";
            ModelCombo.DataSource = OutView;                       
        }


        /// <summary>
        /// Add a background worker to our queue
        /// </summary>
        /// <param name="WorkToPerform">The work to be performed</param>
        /// <param name="Title">The title of our worker</param>
        public void AddBackgroundWorker(DoWorkEventHandler WorkToPerform, String Title)
        {
            BackgroundWorker NewWorker = new BackgroundWorker();
            NewWorker.WorkerReportsProgress = true;
            NewWorker.DoWork += WorkToPerform;            
            WorkerAdded(NewWorker,Title);
            NewWorker.RunWorkerAsync();
        }
        #endregion

        #region Startup activities
        /// <summary>
        /// Load the models into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadModels(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadModels(LoginProcess, this, Model_Collection);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load the blackstart corridors into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadBlackstartCorridors(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadBlackstartCorridors(LoginProcess, this);
                Err = null; return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load the Substations into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadSubstations(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadSubstations(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load the Substations into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadGISSubstations(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadGISSubstations(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }



        /// <summary>
        /// Load the Lines into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadLines(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadLines(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load the Lines into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadGISLines(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadGISLines(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load the Boundaries into memory
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>        
        /// <returns></returns>
        public bool LoadBoundaries(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadBoundaries(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }

        /// <summary>
        /// Load in our KV levels
        /// </summary>        
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadKVLevels(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Db.LoadKVLevels(LoginProcess, this);
                Err = null;
                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }

        }

        /// <summary>
        /// Load the collection of users
        /// </summary>
        /// <param name="LoginProcess"></param>
        /// <param name="Err"></param>
        /// <returns></returns>
        public bool LoadUsers(MM_Login_Process LoginProcess, out Exception Err)
        {
            try
            {
                Err = null;
                User_Collection =  Db.LoadUsers(LoginProcess, this);                
                foreach (MM_Database_User User in User_Collection.Values)
                    if (String.Equals(User.UserName, UserDomain + "\\" + UserName, StringComparison.CurrentCultureIgnoreCase))
                        CurrentUser = User;

                //Now, check to see if we have a user in place. If not, we'll have to add it in
                if (CurrentUser == null)
                {

                    using (DirectoryEntry ADEntry = new DirectoryEntry("LDAP://" + UserDomain))
                    using (DirectorySearcher ADSearch = new DirectorySearcher(ADEntry))
                    {
                        ADSearch.Filter = "(sAMAccountName=" + this.UserName + ")";
                        SearchResult Resp = ADSearch.FindOne();
                        String UserName = this.UserDomain + "\\" + this.UserName;
                        String Email = Resp.Properties["mail"][0].ToString();
                        String FullName = Resp.Properties["givenname"][0].ToString() + " " + Resp.Properties["sn"][0].ToString();
                        String NickName = Resp.Properties["displayname"][0].ToString();
                        NickName = NickName.Substring(NickName.LastIndexOf(' ') + 1);

                        using (frmUserProfileEditor newUser = new frmUserProfileEditor(new MM_Database_User(FullName, UserName, Email, NickName, MM_Database_User.enumUserState.Available, null, this), Db))
                            if (newUser.ShowDialog() == DialogResult.OK)
                            {
                                newUser.EditingUser.WriteRdb(this);
                                CurrentUser = newUser.EditingUser;
                                User_Collection.Add(newUser.EditingUser.ID, newUser.EditingUser);
                                return true;
                            }
                            else
                                return false;
                    }
                }



                return true;
            }
            catch (Exception ex)
            {
                Err = ex;
                return false;
            }
        }
        #endregion
    }
}
